package com.googlecode.ddlutilstool.kernel;

import java.io.File;
import java.io.FileFilter;
import java.io.Reader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.ddlutils.Platform;
import org.apache.ddlutils.PlatformFactory;
import org.apache.ddlutils.io.DataReader;
import org.apache.ddlutils.io.DatabaseDataIO;
import org.apache.ddlutils.io.DatabaseIO;
import org.apache.ddlutils.model.Database;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
import org.xml.sax.InputSource;

import com.googlecode.ddlutilstool.common.ProfileBean;
import com.googlecode.ddlutilstool.ddlutils.ExtendedDatabaseDataIO;

/**
 * <p>A singleton, in charge of executing DDL.</p>
 * 
 * <p>It will spawn a thread to perform the DDL
 * execution, taking in callback for when it is done.</p>
 * 
 * <p>This class completely encapsulates DDL execution and
 * database access.  This is the real heart of the DDLUtilsTool.
 * It deals with the expanding classpath, database connections,
 * and performs all the steps required for the DDL execution.</p>
 * 
 * <p>Notes on how to use DDL:<br>
 * http://db.apache.org/ddlutils/api-usage.html#Reading+from+XML</p>
 * 
 * @author critchie
 *
 */
public class ExecuteManager {

	private static final Logger mLog = Logger.getLogger(ExecuteManager.class);
	private static ExecuteManager mInstance;
	
	public static ExecuteManager getInstance() {
		if (mInstance==null) {
			mInstance = new ExecuteManager();
		}
		return mInstance;
	}
	
	
	private Thread mCurrentJob = null;
	private File mClassPathRoot;
	
	private ExecuteManager() {
	}
	
	/**
	 * Called by the Main class, it just locates the
	 * lib directory for the expanding classpath.
	 */
	void init() {
		mClassPathRoot = new File("./lib");
	}
	
	/**
	 * @return true if a DDL thread is executing.
	 */
	public boolean isBusy() {
		return mCurrentJob!=null;
	}
	
	/**
	 * Called when a thread is done their work, it marks
	 * the Manager as clear and ready for another job.
	 */
	void clearJob() {
		mCurrentJob = null;
	}
	
	/**
	 * Builds a classloader using the "lib" subfolder, if it
	 * exists and contains JAR files.  If it does, it will create
	 * a new classloader containing every file ending with .jar
	 * in the lib folder.
	 * 
	 * @return the classloader used to create the JDBC drivers.
	 * @throws MalformedURLException
	 */
	protected ClassLoader buildClassLoader() throws MalformedURLException {
		if (mClassPathRoot.exists()) {
			if (mClassPathRoot.isDirectory()) {
				File[] jars = mClassPathRoot.listFiles(new FileFilter() {
					public boolean accept(File pFile) {
						return (pFile.isFile() && pFile.getName().toLowerCase().endsWith(".jar"));
					}
				});
				if (jars.length>0) {
					URL[] classPathRoot = new URL[jars.length];
					for (int x=0; x<jars.length; x++) {
						if (mLog.isInfoEnabled()) mLog.info("Adding to classpath: "+jars[x].getName());
						classPathRoot[x] = jars[x].toURI().toURL();
					}
					return new URLClassLoader(classPathRoot);
				}
				else {
					if (mLog.isEnabledFor(Priority.INFO)) mLog.info("No jars found in "+mClassPathRoot.getAbsolutePath()+" folder.  Using default classloader.");
				}
			}
			else {
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Lib folder "+mClassPathRoot.getAbsolutePath()+" not found.  Using default classloader.");
			}
		}
		else {
			if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Lib folder "+mClassPathRoot.getAbsolutePath()+" not found.  Using default classloader.");
		}
		return getClass().getClassLoader();
	}
	
	/**
	 * Creates a JDBC datasource using the profile details and 
	 * the jars in the lib folder.  The datasource is the
	 * apache commons DBCP BasicDataSource.
	 * 
	 * @param pProfile the driver details
	 * @return the datasource
	 * @throws SQLException
	 */
	protected DataSource createDataSource(ProfileBean pProfile) throws SQLException {
		if (pProfile.getClass()==null) {
			throw new SQLException("No Driver Specified.");
		}
		if (pProfile.getUrl()==null) {
			throw new SQLException("No URL Specified.");
		}
		if (pProfile.getUser()==null) {
			throw new SQLException("No User Specified.");
		}
		
		try {
			ClassLoader classLoader = buildClassLoader();
		
			Driver driver = (Driver)classLoader.loadClass(pProfile.getDriver()).newInstance();
			DriverManager.registerDriver(new DriverShim(driver));
			
			BasicDataSource internalDataSource = new BasicDataSource();
			internalDataSource.setDriverClassLoader(classLoader);
			internalDataSource.setDriverClassName(pProfile.getDriver());
			internalDataSource.setUsername(pProfile.getUser());
			internalDataSource.setPassword(pProfile.getPassword());
			internalDataSource.setUrl(pProfile.getUrl());
			internalDataSource.setMaxActive(5);
			internalDataSource.setMaxIdle(5);
			internalDataSource.addConnectionProperty("autoReconnect","true");
			return internalDataSource;
		}
		catch (MalformedURLException e) {
			if (mLog.isEnabledFor(Priority.ERROR)) mLog.error("Error trying to expand classpath: "+e.getMessage());
			throw new SQLException("Error trying to expand classpath: "+e.getMessage());
		} 
		catch (ClassNotFoundException e) {
			if (mLog.isEnabledFor(Priority.ERROR)) mLog.error("Driver class '"+pProfile.getDriver()+"' could not be found: "+e.getMessage());
			throw new SQLException("Driver class '"+pProfile.getDriver()+"' could not be found: "+e.getMessage());
		} 
		catch (InstantiationException e) {
			if (mLog.isEnabledFor(Priority.ERROR)) mLog.error("Driver class '"+pProfile.getDriver()+"' could not be loaded: "+e.getMessage());
			throw new SQLException("Driver class '"+pProfile.getDriver()+"' could not be loaded: "+e.getMessage());
		} 
		catch (IllegalAccessException e) {
			if (mLog.isEnabledFor(Priority.ERROR)) mLog.error("Driver class '"+pProfile.getDriver()+"' could not be accessed: "+e.getMessage());
			throw new SQLException("Driver class '"+pProfile.getDriver()+"' could not be accessed: "+e.getMessage());
		}
	}
	
	/**
	 * Creates a connection to the database using the passed in
	 * driver details and the jars in the lib folder.  This is
	 * called by the test button on the DriverDialog.  It will
	 * throw an exception if it does not work.
	 * 
	 * @param pProfile the driver details.
	 * @throws SQLException
	 */
	public void testProfile(ProfileBean pProfile) throws SQLException {
		DataSource datasource = createDataSource(pProfile);
		Connection c = null;
		try {
			c = datasource.getConnection();
		}
		finally {
			if (c!=null) c.close();
		}
	}
	
	/**
	 * Writes the XML schema file to the database.
	 * 
	 * @param pProfile
	 * @param pXML
	 * @throws Exception
	 */
	public void executeSchemaDDLToDatabase(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteSchemaDDLToDatabase(pListener,pProfile,pXML);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteSchemaDDLToDatabase</p>
	 * 
	 * <p>Updates a database schema to match the DDL Schema XML.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection and a DDL Schema XML file.</li>
	 * <li>Compares the database schema and the DDL schema XML.</li>
	 * <li>Updates the database schema to match the DDL Schema XML.</li>
	 * </ul>
	 */
	class ExecuteSchemaDDLToDatabase extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		Reader mXML;
		
		public ExecuteSchemaDDLToDatabase(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) {
			setName("ExecuteSchemaDDLToDatabase");
			mListener = pListener;
			mProfile = pProfile;
			mXML = pXML;
		}
		
		public void run() {
			try {
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL schema to database...");
				DatabaseIO io = new DatabaseIO();
				io.setValidateXml(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Creating the model from the XML...");
				InputSource is = new InputSource(mXML);
				Database newModel = io.read(is);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(newModel.getName(), null, mProfile.getSchema(), null);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Altering the database...");
		        platform.alterModel(currentModel, newModel, null, true);
		        
		        mListener.finishedExecution(true, "Wrote Schema to database.",null);
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(),null);
			}
			clearJob();
		}
		
	}

	/**
	 * Gets the Profile's database schema, creates the DDL XML and
	 * places it into an editor.
	 * 
	 * @param pProfile
	 * @throws Exception
	 */
	public void executeSchemaDDLToFile(ExecuteCompleteListener pListener, ProfileBean pProfile) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteSchemaDDLToFile(pListener,pProfile);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteSchemaDDLToFile</p>
	 * 
	 * <p>Creates the DDL Schema XML need to recreate a database schema.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection.</li>
	 * <li>Examines the database schema.</li>
	 * <li>Creates the DDL Schema XML that matches the database schema.</li>
	 * </ul>
	 */
	class ExecuteSchemaDDLToFile extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		
		public ExecuteSchemaDDLToFile(ExecuteCompleteListener pListener, ProfileBean pProfile) {
			setName("ExecuteSchemaDDLToDatabase");
			mListener = pListener;
			mProfile = pProfile;
		}
		
		public void run() {
			try {
				StringWriter writer = new StringWriter();
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL schema to file...");
				DatabaseIO io = new DatabaseIO();
				io.setValidateXml(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(mProfile.getName(), null, mProfile.getSchema(), null);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Building the DDL...");
		        io.write(currentModel, writer);
		        
		        mListener.finishedExecution(true, "Created DDL Schema.", writer.toString());
			}
			catch (Throwable e) {
				if (mLog.isEnabledFor(Priority.DEBUG)) mLog.debug(e);
				mListener.finishedExecution(false, e.getMessage(), null);
			}
			clearJob();
		}
		
	}

	/**
	 * Compares the contents of the DDL XML, and the schema of the
	 * database, and create SQL to alter the database to match the
	 * DDL XML.  It places the SQL into an editor window.
	 * 
	 * @param pListener
	 * @param pProfile
	 * @param pXML
	 * @throws Exception
	 */
	public void executeAlterSchemaDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteAlterSchemaDDLToSQL(pListener,pProfile, pXML);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteAlterSchemaDDLToSQL</p>
	 * 
	 * <p>Create SQL to alter a database schema to match DDL XML.</p>
	 * 
	 * <ul>
	 * <li>Takes in DDL Schema XML and a database connection.</li>
	 * <li>Compares the schema and the DDL.</li>
	 * <li>Constructs the SQL required to alter the database to match the DDL.</li>
	 * </ul>
	 */
	class ExecuteAlterSchemaDDLToSQL extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		Reader mXML;
		
		public ExecuteAlterSchemaDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) {
			setName("ExecuteSchemaDDLToSQL");
			mListener = pListener;
			mProfile = pProfile;
			mXML = pXML;
		}
		
		public void run() {
			try {
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL schema to SQL...");
				DatabaseIO io = new DatabaseIO();
				io.setValidateXml(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Set the DDL Platform to script mode...");
				platform.setScriptModeOn(true);
				if (platform.getPlatformInfo().isSqlCommentsSupported()) {
	                platform.setSqlCommentsOn(true);
	            }
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Creating the model from the XML...");
				InputSource is = new InputSource(mXML);
				Database newModel = io.read(is);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(newModel.getName(), null, mProfile.getSchema(), null);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Creating SQL...");
		        String sql = platform.getAlterModelSql(currentModel, newModel, null);
		        
		        mListener.finishedExecution(true, "Wrote Schema to SQL.", sql);
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(), null);
			}
			clearJob();
		}
		
	}

	/**
	 * Create SQL to create a a database schema.
	 * 
	 * @param pListener
	 * @param pProfile
	 * @throws Exception
	 */
	public void executeCreateSchemaDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteCreateSchemaDDLToSQL(pListener,pProfile);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteCreateSchemaDDLToSQL</p>
	 * 
	 * <p>Create SQL to create a a database schema.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection.</li>
	 * <li>Examines the database schema.</li>
	 * <li>Constructs the SQL required to recreate the database.</li>
	 * </ul>
	 */
	class ExecuteCreateSchemaDDLToSQL extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		
		public ExecuteCreateSchemaDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile) {
			setName("ExecuteSchemaDDLToSQL");
			mListener = pListener;
			mProfile = pProfile;
		}
		
		public void run() {
			try {
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL schema to SQL...");
				DatabaseIO io = new DatabaseIO();
				io.setValidateXml(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Set the DDL Platform to script mode...");
				platform.setScriptModeOn(true);
				if (platform.getPlatformInfo().isSqlCommentsSupported()) {
	                platform.setSqlCommentsOn(true);
	            }
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(mProfile.getName(), null, mProfile.getSchema(), null);
		
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Creating SQL...");
		        String sql = platform.getCreateModelSql(currentModel, false, true);
		        
		        mListener.finishedExecution(true, "Wrote Schema to SQL.", sql);
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(), null);
			}
			clearJob();
		}
		
	}

	/**
	 * Writes the XML data file to the database.
	 * 
	 * @param pProfile
	 * @param pXML
	 * @throws Exception
	 */
	public void executeDataDDLToDatabase(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteDataDDLToDatabase(pListener,pProfile,pXML);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteDataDDLToDatabase</p>
	 * 
	 * <p>Execute DDL Data XML, adding records to a database.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection and a DDL Data XML file.</li>
	 * <li>Inserts the data from the DDL file into the database.</li>
	 * </ul>
	 */
	class ExecuteDataDDLToDatabase extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		Reader mXML;
		
		public ExecuteDataDDLToDatabase(ExecuteCompleteListener pListener, ProfileBean pProfile, Reader pXML) {
			setName("ExecuteDataDDLToDatabase");
			mListener = pListener;
			mProfile = pProfile;
			mXML = pXML;
		}
		
		public void run() {
			DataReader dataReader = null;
			try {
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL data to database...");
				DatabaseDataIO io = new DatabaseDataIO();
				io.setUseBatchMode(false);
				io.setEnsureFKOrder(true);
				io.setFailOnError(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(mProfile.getName(), null, mProfile.getSchema(), null);
		
		        if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Writing the data...");
				dataReader = io.getConfiguredDataReader(platform, currentModel);
	            dataReader.getSink().start();
	            io.writeDataToDatabase(dataReader, mXML);

	            mListener.finishedExecution(true, "Wrote Data to database.",null);
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(),null);
			}
			finally {
				if (dataReader!=null && dataReader.getSink()!=null) {
	                try {
	                	dataReader.getSink().end();
	                }
	                catch (Throwable t) {
	                	//connection was probably already closed.
	                	if (mLog.isEnabledFor(Priority.DEBUG)) mLog.debug("Error closing sink: "+t.getMessage());
	                }
	            }				
			}
			clearJob();
		}
		
	}

	/**
	 * Gets the Profile's database data, creates the DDL XML and
	 * places it into the editor.
	 * 
	 * @param pProfile
	 * @throws Exception
	 */
	public void executeDataDDLToFile(ExecuteCompleteListener pListener, ProfileBean pProfile) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteDataDDLToFile(pListener,pProfile);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteDataDDLToFile</p>
	 * 
	 * <p>Creates the DDL Data XML matching a database.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection.</li>
	 * <li>Creates the DDL DataXML matching the database.</li>
	 * <li>Outputs the DDL to a file.</li>
	 * </ul>
	 */
	class ExecuteDataDDLToFile extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		
		public ExecuteDataDDLToFile(ExecuteCompleteListener pListener, ProfileBean pProfile) {
			setName("ExecuteDataDDLToDatabase");
			mListener = pListener;
			mProfile = pProfile;
		}
		
		public void run() {
			try {
				StringWriter writer = new StringWriter();
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL data to file...");
				DatabaseDataIO io = new DatabaseDataIO();
				io.setUseBatchMode(false);
				io.setEnsureFKOrder(true);
				io.setFailOnError(false);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(mProfile.getName(), null, mProfile.getSchema(), null);
		
		        if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Building the DDL...");
		        io.writeDataToXML(platform, currentModel, writer, "UTF-8");
		        
		        mListener.finishedExecution(true, "Created DDL Schema.", writer.toString());
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(), null);
			}
			clearJob();
		}
		
	}

	/**
	 * Creates SQL insert statements matching a database
	 * 
	 * @param pListener
	 * @param pProfile
	 * @throws Exception
	 */
	public void executeDataDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile) throws Exception {
		if (isBusy()) {
			throw new Exception("Already running a job.");
		}
		mCurrentJob = new ExecuteDataDDLToSQL(pListener,pProfile);
		mCurrentJob.start();
	}
	
	/**
	 * <p>Class ExecuteDataDDLToSQL</p>
	 * 
	 * <p>Creates SQL insert statements matching a database.</p>
	 * 
	 * <ul>
	 * <li>Takes in a database connection.</li>
	 * <li>Creates the SQL matching the database.</li>
	 * <li>Outputs the SQL as INSERT statements to a file.</li>
	 * </ul>
	 */
	class ExecuteDataDDLToSQL extends Thread {
		ExecuteCompleteListener mListener;
		ProfileBean mProfile;
		
		public ExecuteDataDDLToSQL(ExecuteCompleteListener pListener, ProfileBean pProfile) {
			setName("ExecuteDataDDLToSQL");
			mListener = pListener;
			mProfile = pProfile;
		}
		
		public void run() {
			try {
				StringWriter writer = new StringWriter();
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Trying to write DDL data to SQL...");
				ExtendedDatabaseDataIO io = new ExtendedDatabaseDataIO();
				io.setUseBatchMode(false);
				io.setEnsureFKOrder(true);
				io.setFailOnError(false);
				
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the datasource...");
				DataSource datasource = createDataSource(mProfile);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Getting the DDL Platform...");
				Platform platform = PlatformFactory.createNewPlatformInstance(datasource);
				
				if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Reading the existing model from the database...");
		        Database currentModel = platform.readModelFromDatabase(mProfile.getName(), null, mProfile.getSchema(), null);

		        
		        if (mLog.isEnabledFor(Priority.INFO)) mLog.info("Building the insert SQL...");
		        io.writeDataToSQL(platform, currentModel, writer);
		        
		        mListener.finishedExecution(true, "Wrote Data to SQL.", writer.toString());
			}
			catch (Throwable e) {
				mListener.finishedExecution(false, e.getMessage(), null);
			}
			clearJob();
		}
		
	}

}
